package com.woniu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.entity.Comment;
import com.woniu.mapper.CommentMapper;
import com.woniu.service.CommentService;
import com.woniu.service.vo.CommentVo;
import com.woniu.service.vo.TestPageVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author D
 * @since 2023-03-27 08:24:57
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 根据靶场code按时间倒序查询当前靶场的评论，封装map，判断是否有子评论，存入Redis，并封装到TestPageVo中
     *
     * @param testCode 靶场编号
     * @param currentPage 当前页
     * @param pageSize 每页显示的条数
     * @param userCode 用户名
     * @return 返回封装好的TestPageVo
     */
    @Override
    public TestPageVo<CommentVo> getCommentByTestCode(Long testCode, Long currentPage, Long pageSize, String userCode) {
        if (currentPage == null || currentPage < 1L) {
            currentPage = 1L;
        }
        if (pageSize == null || pageSize < 5L) {
            pageSize = 5L;
        }
        //获取评论数据
        Page<Comment> page = new Page<>(currentPage, pageSize);
        QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("test_code", testCode);

        queryWrapper.orderByDesc("comment_create_time");
        Page<Comment> commentPage = commentMapper.selectPage(page, queryWrapper);

        List<Comment> commentList = commentPage.getRecords();
        List<CommentVo> commentVoList = new ArrayList<>();
        Map<Long, CommentVo> map = new HashMap<>();

        //把comment转化为commentVo
        for (Comment comment : commentList) {
            CommentVo commentVo = new CommentVo();
            BeanUtils.copyProperties(comment, commentVo);
            commentVo.setChildren(new ArrayList<>());
            commentVoList.add(commentVo);
            map.put(commentVo.getId(), commentVo);
        }

        //给评论添加回复
        map.forEach((id, commentVo) -> {
            CommentVo parent = map.get(commentVo.getParentId());
            if (parent != null) {
                parent.getChildren().add(commentVo);
            }
        });

        //提取父评论
        List<CommentVo> voList = map.values().stream().filter(commentVo -> {
            return commentVo.getParentId() == -1;
        }).sorted(Comparator.comparing(CommentVo::getCommentCreateTime).reversed()).collect(Collectors.toList());

        TestPageVo<CommentVo> testPageVo = new TestPageVo<>();
        testPageVo.setPageVo(voList).setPages(commentPage.getPages()).setTotal(commentPage.getTotal()).setCurrentPage(commentPage.getCurrent()).setSize(commentPage.getSize());


        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();

        testPageVo.getPageVo().forEach(this::initialize);

        TestPageVo<CommentVo> commentByTest = (TestPageVo<CommentVo>) opsForValue.get("-" + userCode + "comment" + testCode);
        if (commentByTest == null) {
            opsForValue.set("-" + userCode + "comment" + testCode, testPageVo,1, TimeUnit.DAYS);
            return testPageVo;
        }
        //同步redis和数据库的数据
        for (CommentVo commentVo : commentByTest.getPageVo()) {
            for (CommentVo comment : testPageVo.getPageVo()) {
                if (commentVo.getId().equals(comment.getId())) {
                    commentVo.setDisplay(comment.getDisplay());
                    comment.setIsLike(commentVo.getIsLike());
                    BeanUtils.copyProperties(commentVo, comment);

                }
            }
        }
        opsForValue.set("-" + userCode + "comment" + testCode, testPageVo,1,TimeUnit.DAYS);

        return testPageVo;
    }


    /**
     * 递归设置子评论的点赞数和是否点赞
     * @param commentVo 评论对象
     */
    private void initialize(CommentVo commentVo) {
        commentVo.setIsLike(0);
        if (commentVo.getLikeNumber() == null) {
            commentVo.setLikeNumber(0);
        }
        if (commentVo.getChildren() != null) {
            commentVo.getChildren().forEach(this::initialize);
        }
    }
}
